package com.sca4cloud.sca.filter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

import com.sca4cloud.sca.common.core.constant.CacheConstants;
import com.sca4cloud.sca.common.core.constant.CommonConstants;
import com.sca4cloud.sca.common.core.constant.SecurityConstants;
import com.sca4cloud.sca.common.core.constant.enums.EncFlagTypeEnum;
import com.sca4cloud.sca.common.core.util.WebUtils;
import com.sca4cloud.sca.common.gateway.config.GatewayConfigProperties;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 密码解密工具类
 * <p>
 * 参考 ModifyRequestBodyGatewayFilterFactory 实现
 */
@Slf4j
@Component
@RequiredArgsConstructor
@WebFilter(urlPatterns = "/*")
public class PasswordDecoderFilter implements Filter {

    private static final String PASSWORD = "password";
    private static final String KEY_ALGORITHM = "AES";

//    @Autowired
//    private RedisTemplate<String, Object> redisTemplate;
//
//    @Value("${gateway.encode-key:scaxscaxscaxscax}")
//    private String encodeKey;
    
    private final RedisTemplate<String, Object> redisTemplate;

	private final GatewayConfigProperties gatewayConfig;
    // @Autowired
    // private FilterIgnoreConfig filterIgnoreConfig;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        String url = request.getRequestURI();
        // 不是登录请求，直接向下执行
        if (!StrUtil.containsAnyIgnoreCase(url, SecurityConstants.OAUTH_TOKEN_URL)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 2.刷新token，直接向下执行
        String grantType = request.getParameter("grant_type");
        if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 3. 判断客户端是否需要解密，明文传输直接向下执行
        if (!isEncClient(request)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }

        String pwd = request.getParameter(PASSWORD);
        String newPwd = decryptAES(pwd);
        log.info("请求  PasswordDecoderFilter   url={}", url);
        HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {

            @Override
            public Map<String, String[]> getParameterMap() {
                Map<String, String[]> map = new HashMap(super.getParameterMap());
                map.put(PASSWORD, new String[] {newPwd.trim()});
                // log.info("getParameterMap Map()={}",JSON.toJSON(map));
                return map;
            }

        };
        chain.doFilter(requestWrapper, servletResponse);
    }

    /**
     * 根据请求的clientId 查询客户端配置是否是加密传输
     * 
     * @param request
     *            请求上下文
     * @return true 加密传输 、 false 原文传输
     */
    private boolean isEncClient(HttpServletRequest request) {
        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        String clientId = WebUtils.extractClientId(header).orElse(null);
        // 获取租户拼接区分租户的key
        String tenantId = request.getHeader(CommonConstants.TENANT_ID);
        String key = String.format("%s:%s:%s", StrUtil.isBlank(tenantId) ? CommonConstants.TENANT_ID_1 : tenantId,
            CacheConstants.CLIENT_FLAG, clientId);

        Object val = redisTemplate.opsForValue().get(key);

        // 当配置不存在时，默认需要解密
        if (val == null) {
            return true;
        }

        JSONObject information = JSONUtil.parseObj(val.toString());
        if (StrUtil.equals(EncFlagTypeEnum.NO.getType(), information.getStr(CommonConstants.ENC_FLAG))) {
            return false;
        }
        return true;
    }

    /**
     * 原文解密
     *
     * @return
     */
    private String decryptAES(String pwd) {
        String password = "";
        // 构建前端对应解密AES 因子
        AES aes = new AES(Mode.CBC, Padding.NoPadding, new SecretKeySpec(gatewayConfig.getEncodeKey().getBytes(), KEY_ALGORITHM),
            new IvParameterSpec(gatewayConfig.getEncodeKey().getBytes()));
        byte[] result = aes.decrypt(Base64.decode(pwd));
        return new String(result, StandardCharsets.UTF_8);
    }

}
